﻿/*
 * 【作者】郝伟老师
 * 【使用】并发缓冲日志记录类。
 * 【说明】
 *  用于并发的带有缓冲的日志记录，可以提高并发性，大约每秒可以写入10万条日志记录（取决于磁盘性能）。
 * 
 * 
 * 
 * 【历史更新记录】
 * 2019/06/14   V1.0    初步建立此类。 
 * 
 * 
 */
 
 using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WindGoes6.Data.Logs
{
    /// <summary>
    /// This class is used to manage logs from the same program.
    /// It has a key method AddLog to receive log. This is a 
    /// multi-threading class to save logs into a file in specified 
    /// seconds to avoid save logs too frequently. 
    /// </summary>
    public class LogManager
    {
        /// <summary>
        /// The file path to store log.
        /// </summary>
        public string LogFilePath { get; set; } = "system.log";

        /// <summary>
        /// The interval (in second) of saving logs into file.
        /// </summary>
        public int SaveInterval { get; set; } = 1;

        // To contronl the running status of the thread
        bool isRunning = false;

        // Teporary log list for holding current logs.
        List<Log> logs = new List<Log>();

        // The thread to perform method process() 
        Thread thread;

        /// <summary>
        /// Construct a LogManager object.
        /// </summary>
        public LogManager()
        {

        }

        /// <summary>
        /// Construct a LogManager object.
        /// </summary>
        /// <param name="logPath">The file path to store logs.</param>
        /// <param name="saveInterval">Writing intervl.</param>
        public LogManager(string logPath, int saveInterval = 10)
        {
            LogFilePath = logPath;
            SaveInterval = saveInterval;
        }

        /// <summary>
        /// Add log with logtype, method info and arguemtns.
        /// </summary>
        /// <param name="logType">Log Type</param>
        /// <param name="methondInfo">Method Information</param>
        /// <param name="args"></param>
        public void AddLog(int logType, string methondInfo, string[] args)
        {
            AddLog(logType, methondInfo, args);
        }

        /// <summary>
        /// Add a new log.
        /// </summary>
        /// <param name="logType">The type of this log.</param>
        /// <param name="args">The arguments of this log.</param>
        public void AddLog(int logType, string[] args)
        {
            AddLog(new Log(logType, args));
        }


        /// <summary>
        /// Add a new log.
        /// </summary>
        /// <param name="log">The log to be added.</param>
        public void AddLog(Log log)
        {
            lock (this)
            {
                logs.Add(log);
            }
        }

        /// <summary>
        /// main method to process logs.
        /// </summary>
        private void Process()
        {
            isRunning = true;
            while (isRunning)
            {
                WriteLogsToFile(); 
                Thread.Sleep(SaveInterval);
            }
            WriteLogsToFile();
        }

        /// <summary>
        /// Write logs into the specified file.
        /// </summary>
        public void WriteLogsToFile()
        {
            if (logs.Count > 0)
            {
                // Obtain all logs and release lock
                List<Log> loglist = new List<Log>();
                lock (this)
                {
                    loglist.AddRange(logs);
                    logs.Clear();
                }

                // append new logs into log file.
                using (StreamWriter fw = new StreamWriter(LogFilePath, true, Encoding.UTF8))
                {
                    foreach (Log log in loglist)
                        fw.WriteLine(log);
                }
            }
        }

        /// <summary>
        /// Starts thread of this log manager. 
        /// </summary>
        public void Start()
        {
            if (thread != null)
                return;

            thread = new Thread(Process);
            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// Stops the thread of this log manager. 
        /// </summary>
        public void Stop()
        {
            isRunning = false;
        } 
    }

}
